
/*
	NounEnhancement.cpp
	(c)2008 Palestar Inc, Jeff Everett
*/


#include "Debug/Assert.h"
#include "Constants.h"
#include "NounShip.h"
#include "NounPlanet.h"
#include "StructurePort.h"
#include "GameContext.h"
#include "NounEnhancement.h"
#include "NounEnhancementSpecials.h"
#include "GameProfile.h"


Material::Link		NounEnhancement::m_Icons[System::ES_SYSTEMCOUNT][ModifierType::MT_MODIFIERCOUNT];
bool				NounEnhancement::m_bInitialized = false;

const Color	COLOR_COMMON(15,217,26,255);
const Color	COLOR_RARE (108,108,255,255);
const Color	COLOR_ULTRA_RARE (193,0,193,255);

IMPLEMENT_ABSTRACT_FACTORY( NounEnhancement, NounGame );

BEGIN_ABSTRACT_PROPERTY_LIST( NounEnhancement, NounGame )
END_PROPERTY_LIST();

//---------------------------------------------------------------------------------------------------

NounEnhancement::Enhancement::Enhancement(System a_system, ModifierType a_modifier, int a_amount)
{
	m_System = a_system;
	m_Modifier = a_modifier;
	m_Amount = a_amount;
}

//---------------------------------------------------------------------------------------------------

bool NounEnhancement::read(InStream &input)
{
	return NounGame::read(input);
}

//---------------------------------------------------------------------------------------------------

NounType NounEnhancement::nounType() const
{
	return TYPE_OBJECT;
}

//---------------------------------------------------------------------------------------------------

int NounEnhancement::enhancementCount() const
{
	return m_enhancements.size();
}

Material * NounEnhancement::icon() const
{
	// for now we are just returning icon of the first modifier
	// eventually i will add a virtual icon to each enhancement 
	// so each can decide which to show
	return m_Icons[GetSystem(0)][GetModifier(0)];
}

Color NounEnhancement::color() const
{
	Rarity r = rarity();
	if(r == RARITY_RARE)
		return COLOR_RARE;
	else if(r == RARITY_ULTRA_RARE)
		return COLOR_ULTRA_RARE;
	return COLOR_COMMON;
}

CharString NounEnhancement::status() const
{
	CharString sDesc;

	for(int i=0;i<(int)m_enhancements.size();i++)
	{
		int nAmount = GetAmount(i);
		if(GetModifier(i) != MT_REFILL)
		{
			if(nAmount > 0)
			{
				sDesc += "Increase ";
			}
			else if(nAmount < 0)
			{
				sDesc += "Decrease ";
				// need to make this positive for the display
				nAmount += (nAmount*-2);
			}
		}

		sDesc += NounEnhancement::GetInfo(GetSystem(i),GetModifier(i));

		if(nAmount != 0)
			sDesc += CharString().format("%d%%\n",nAmount);
		else
			sDesc += "\n";
	}

	if(IsUnique())
		sDesc += "<color;ff0000ff>  UNIQUE</color>";
	return sDesc;
}

NounEnhancement::System NounEnhancement::GetSystem(int a_index) const
{
	if(a_index >= 0 && a_index < (int)m_enhancements.size())
		return m_enhancements[a_index]->m_System;
	return System::ES_NONE;
}
NounEnhancement::ModifierType NounEnhancement::GetModifier(int a_index) const
{
	if(a_index >= 0 && a_index < (int)m_enhancements.size())
		return m_enhancements[a_index]->m_Modifier;
	return ModifierType::MT_DAMAGE;

}

int	NounEnhancement::GetAmount(int a_index) const
{
	if(a_index >= 0 && a_index < (int)m_enhancements.size())
		return m_enhancements[a_index]->m_Amount;
	return 0;
}

CharString NounEnhancement::GetDescription() const
{
	// only the requirements are displayed in teh description since it is used by tool tips
	CharString sDesc = CharString().format("<large><color;%6.6x>%s</color></large>\n",color().RGB(),GetName());
	for(int i=0;i<(int)m_enhancements.size();i++)
	{
		sDesc += "  ";
		int nAmount = GetAmount(i);
		if(GetModifier(i) != MT_REFILL && GetSystem(i) != ES_TRAIL && GetSystem(i) != ES_DEFENSE)
		{
			if(nAmount > 0)
			{
				sDesc += "Increase ";
			}
			else if(nAmount < 0)
			{
				sDesc += "Decrease ";
				// need to make this positive for the display
				nAmount += (nAmount*-2);
			}
		}

		sDesc += NounEnhancement::GetInfo(GetSystem(i),GetModifier(i));

		if(GetSystem(i) == ES_TRAIL)
		{
			switch(GetAmount(i))
			{
			case 0:
				sDesc += "Purple\n";
				break;
			case 1:
				sDesc += "Green\n";
				break;
			case 2:
				sDesc += "Red\n";
				break;
			case 3:
				sDesc += "Blue\n";
				break;
			}
		}
		else if(nAmount != 0)
			sDesc += CharString().format("%d%%\n",nAmount);
		else
			sDesc += "\n";
	}

	unsigned int flags = requirementFlags();
	if(testFlags(REQ_SUBSCRIBER))
	{
		sDesc += "<color;ff00ff00>  Subscribers Only\n</color>";
	}
	else if(testFlags(REQ_ADMIN))
	{
		sDesc += "<color;ff00ff00>  Ships: ADMIN ONLY\n</color>";
	}

	if(flags & REQ_ENGINEER && 
		flags & REQ_SUPPLY &&
		flags & REQ_TRANSPORT &&
		flags & REQ_SCOUT &&
		flags & REQ_FRIGATE &&
		flags & REQ_DESTROYER &&
		flags & REQ_CRUISER &&
		flags & REQ_DREAD &&
		flags & REQ_STATION)
	{
		sDesc += "<color;ffffffff>  Ships: <color;ff50ff50>Any\n</color></color>";
	}
	else
	{
		sDesc += "<color;ffffffff>  Ships: <color;ff50ff50>";
		if(testFlags(REQ_ENGINEER))
			sDesc += "Engineer ";
		if(testFlags(REQ_SUPPLY))
			sDesc += "Supply ";
		if(testFlags(REQ_TRANSPORT))
			sDesc += "Transport ";
		if(testFlags(REQ_SCOUT))
			sDesc += "Scout ";
		if(testFlags(REQ_FRIGATE))
			sDesc += "Frigate ";
		if(testFlags(REQ_DESTROYER))
			sDesc += "Destroyer ";
		if(testFlags(REQ_CRUISER))
			sDesc += "Cruiser ";
		if(testFlags(REQ_DREAD))
			sDesc += "Dreadnaught ";
		if(testFlags(REQ_STATION))
			sDesc += "Station ";
		sDesc += "\n</color></color>";
	}

	if(IsUnique())
		sDesc += "<color;ff0000ff>  UNIQUE\n</color>";


	return sDesc;
}

bool NounEnhancement::canApply(NounShip *a_pShip) const
{

	// is this enhancement unique?
	if(IsUnique())
	{
		// if it is, make sure another one isnt on this ship
		for(int i=0;i<a_pShip->childCount();i++)
		{
			// if this enhancement already is on the ship, we cant add another
			if(a_pShip->child(i)->factory()->classKey() == factory()->classKey() )
				return false;
		}
	}


	// can only have 1 trail
	for(int nEnh = 0;nEnh < enhancementCount();nEnh++)
	{
		// if this is a trail
		if(GetSystem(nEnh) == ES_TRAIL)
		{
			for(int i=0;i<a_pShip->childCount();i++)
			{
				NounEnhancement *pEnh= WidgetCast<NounEnhancement>(a_pShip->child(i));
				// if this is an enhancement see if we already have a trail modifier
				if(pEnh)
				{
					for(int childEnh = 0;childEnh < pEnh->enhancementCount();childEnh++)
					{
						if(pEnh->GetSystem(childEnh) == ES_TRAIL)
							return false;
					}
				}
			}
		}
	}

	unsigned int flags = requirementFlags();

	if(flags & REQ_ADMIN)
	{
		int userId = a_pShip->userId();
		// if its req admin, we dont care about any other req
		if(userId > 0)
			return true;
		return false;
	}
	if(flags & REQ_SUBSCRIBER)
	{
		// rank = is unsubscribbed
		if(a_pShip->rank() == -2)
			return false;
	}

	NounShip::Type type = a_pShip->type();

	if(type == NounShip::ENGINEER && flags & REQ_ENGINEER)
		return true;
	if(type == NounShip::SUPPLY && flags & REQ_SUPPLY)
		return true;
	if(type == NounShip::TRANSPORT && flags & REQ_TRANSPORT)
		return true;
	if(type == NounShip::SCOUT && flags & REQ_SCOUT)
		return true;
	if(type == NounShip::FRIGATE && flags & REQ_FRIGATE)
		return true;
	if(type == NounShip::DESTROYER && flags & REQ_DESTROYER)
		return true;
	if(type == NounShip::CRUISER && flags & REQ_CRUISER)
		return true;
	if(type == NounShip::DREAD && flags & REQ_DREAD)
		return true;
	if(type == NounShip::STATION && flags & REQ_STATION)
		return true;


	return false;
}


//---------------------------------------------------------------------------------------------------

dword NounEnhancement::requirementFlags() const
{
	return REQ_ANY;
}

NounEnhancement::Rarity NounEnhancement::rarity() const
{
	return RARITY_COMMON;
}

bool NounEnhancement::IsUnique() const
{
	return false;
}

void NounEnhancement::onUse(NounShip *a_pShip)
{
	for(int i=0;i<(int)m_enhancements.size();i++)
	{
		switch(GetSystem(i))
		{
		case ES_JUMPDRIVE:
			enhanceJumpDrive(a_pShip,i);
			break;
		case ES_SHIPENERGY:
			enhanceShipEnergy(a_pShip,i);
			break;
		default:
			break;
		}
	}
}

bool NounEnhancement::enhanceJumpDrive(NounShip *a_pShip, int a_index)
{
	ModifierType modifier = GetModifier(a_index);
	GadgetJumpDrive *pDrive =  a_pShip->jumpDrive();

	int amount = GetAmount(a_index);

	if(modifier == MT_REFILL)
	{
		if(pDrive)
		{
			pDrive->refuel(amount);
			return true;
		}
	}
	return false;
}

bool NounEnhancement::enhanceShipEnergy(NounShip *a_pShip, int a_index)
{
	ModifierType modifier = GetModifier(a_index);
	int amount = GetAmount(a_index);

	if(modifier == MT_REFILL)
	{
		if(a_pShip)
		{
			a_pShip->refuelEnergy(amount);
			return true;
		}
	}
	return false;
}

bool NounEnhancement::testFlags( dword test ) const
{
	return (requirementFlags() & test) != 0;
}

//---------------------------------------------------------------------------------------------------

CharString NounEnhancement::GetInfo(NounEnhancement::System a_system, NounEnhancement::ModifierType a_modifier)
{
	CharString sDesc;
	switch(a_system)
	{
		case ES_BEAM:
			sDesc += "Beam ";
			break;
		case ES_ARMOR:
			sDesc += "Armor ";
			break;
		case ES_AUTOREPAIR:
			sDesc += "Autorepair ";
			break;
		case ES_BUILD:			
			sDesc += "Build Time ";
			break;
		case ES_CLOAK:			
			sDesc += "Cloak ";
			break;
		case ES_DRIVE:			
			sDesc += "Drive ";
			break;
		case ES_ECCM:			
			sDesc += "ECCM ";
			break;
		case ES_ECM:			
			sDesc += "ECM ";
			break;
		case ES_FIGHTERS:			
			sDesc += "Fighter ";
			break;
		case ES_JUMPDRIVE:		
			sDesc += "Jumpdrive ";
			break;
		case ES_JUMPGATE:			
			sDesc += "Jumpgate ";
			break;
		case ES_MINING:	
			sDesc += "Mining ";
			break;
		case ES_PULSESHIELD:
			sDesc += "Pulse Shield ";
			break;
		case ES_REACTOR:			
			sDesc += "Reactor ";
			break;
		case ES_RELOAD:		
			sDesc += "Reload ";
			break;
		case ES_SCANNER:			
			sDesc += "Scanner ";
			break;
		case ES_SHIELD:		
			sDesc += "Shields ";
			break;
		case ES_TRACTOR:			
			sDesc += "Tractor ";
			break;
		case ES_WEAPON:
			sDesc += "Projectile ";
			break;
		case ES_VELOCITY:
			sDesc += "Max Ship Speed ";
			break;
		case ES_THRUST:
			sDesc += "Ship Thrust ";
			break;
		case ES_TURNRATE:
			sDesc += "Turn Rate ";
			break;
		case ES_SHIPENERGY:
			sDesc += "Ship Energy ";
			break;
		case ES_TRAIL:
			sDesc += "Modify Thruster Trail: ";
			break;
		case ES_DEFENSE:
			sDesc += "Reduce Damage by ";
			break;
		default:
			sDesc += "Unknown System ";
	}

	switch(a_modifier)
	{
		case MT_RANGE:
			sDesc += "Range: ";
			break;
		case MT_COOLDOWN:
			sDesc += "Energy Charge Rate: ";
			break;
		case MT_DAMAGE:
			sDesc += "Damage: ";
			break;
		case MT_ENERGY:
			sDesc += "Energy Usage: ";
			break;
		case MT_REFILL:
			sDesc += "Refill: ";
			break;
		case MT_INCREASE:
		case MT_APPLY:
			break;
		default:
			sDesc += "Unknown Modifier ";
	}
	return sDesc;
}



void NounEnhancement::InitializeIcons()
{
	if(m_bInitialized)
		return;

	// Load Icons
	loadResource("interface\\icons\\enh_weapondamage.prt",m_Icons[ES_WEAPON][MT_DAMAGE]);
	loadResource("interface\\icons\\enh_weaponrange.prt",m_Icons[ES_WEAPON][MT_RANGE]);
	loadResource("interface\\icons\\enh_weaponenergy.prt",m_Icons[ES_WEAPON][MT_ENERGY]);
	loadResource("interface\\icons\\enh_weaponcooldown.prt",m_Icons[ES_WEAPON][MT_COOLDOWN]);
	loadResource("interface\\icons\\enh_beamdamage.prt",m_Icons[ES_BEAM][MT_DAMAGE]);
	loadResource("interface\\icons\\enh_beamrange.prt",m_Icons[ES_BEAM][MT_RANGE]);
	loadResource("interface\\icons\\enh_beamenergy.prt",m_Icons[ES_BEAM][MT_ENERGY]);
	loadResource("interface\\icons\\enh_beamcooldown.prt",m_Icons[ES_BEAM][MT_COOLDOWN]);

	loadResource("interface\\icons\\enh_shipvelocity.prt",m_Icons[ES_VELOCITY][MT_INCREASE]);
	loadResource("interface\\icons\\enh_shipthrust.prt",m_Icons[ES_THRUST][MT_INCREASE]);
	loadResource("interface\\icons\\enh_shipturn.prt",m_Icons[ES_TURNRATE][MT_INCREASE]);
	loadResource("interface\\icons\\enh_shipshield.prt",m_Icons[ES_SHIELD][MT_INCREASE]);
	loadResource("interface\\icons\\enh_shiparmor.prt",m_Icons[ES_ARMOR][MT_INCREASE]);
	
	loadResource("interface\\icons\\enh_jumpdriverefill.prt",m_Icons[ES_JUMPDRIVE][MT_REFILL]);
	loadResource("interface\\icons\\enh_energyrefuel50.prt",m_Icons[ES_SHIPENERGY][MT_REFILL]);

	loadResource("interface\\icons\\enh_buildicon.prt",m_Icons[ES_BUILD][MT_INCREASE]);
	loadResource("interface\\icons\\enh_trail.prt",m_Icons[ES_TRAIL][MT_APPLY]);
	loadResource("interface\\icons\\enh_shipshield.prt",m_Icons[ES_DEFENSE][MT_INCREASE]);

	// validate icons
	for(int system = 0;system < ES_SYSTEMCOUNT;system++)
	{
		for(int modifier =0;modifier< MT_MODIFIERCOUNT;modifier++)
		{
			if(!m_Icons[system][modifier].valid())
			{
				loadResource("interface\\icons\\team.prt",m_Icons[system][modifier]);
			}
		}
	}

	m_bInitialized = true;

}

//---------------------------------------------------------------------------------------------------
// EOF
